/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package biofilter.data.Sequence;

import biofilter.util.*;
import java.math.BigInteger;
import java.util.*;

/**
 * A BioSequence is an abstract class definition for biosequences (DNA, RNA and Prot).
 * This class presents useful utility for records and other sequence based attributes
 * @author Daniel Quest
 * @date   Jan 11 2009
 */
public abstract class BioSequence {
    protected StringBuffer sb = null;
    protected String sequence = null;
    protected SequencePosition sp = null;  /** Important, this sequence position starts at 1 and ends at the end of the sequence! -- it is here to allow sequence math, not to store any relative postions, relative postions belong in a list */
    protected String topology=""; //e.g. linear
    protected String type="";     //e.g. mRNA
    public BioSequence(){
        init();
    }
    public BioSequence(String s){
        set(s);
    }

    public void init(){
        set("");
    }
    public void  set(String s){
        set(s,'+');
    }
    public void set(String s, char strand){
        sequence = s;
        sp = new SequencePosition();
        sp.set(1, 1 + sequence.length(), strand);
    }
    public String get(){
        if(sequence == null && sb == null){
            sequence = "";
        }else if(sequence == null){
            sequence = sb.toString();
        }
        return sequence;
    }
    public void setStrand(char c){
        if(c == '+')
            sp.setStrand('+');
        else if(c=='-')
            sp.setStrand('-');
        else
            sp.setStrand('.');
    }
    public void append(String addPart){
        if(sb == null){
            sb = new StringBuffer();
            sb.append(sequence);
            sequence = null;
        }
        sb.append(addPart);
    }
    public int size(){
        if(sequence == null && sb == null){
            sequence = "";
        }else if(sequence == null){
            sequence = sb.toString();
        }
        return sequence.length();
    }

    /**
     * converts this.record, a string of sequence characters into an embl
     * - 60 char
     * - 10 break
     * - numirical labeled sequence
     * e.g. converts:
     * aaacaaaccaaatatggattttattgtagccatatttgctctgtttgttattagctcattcacaattacttccacaaatgcagttgaagcttctactcttcttgacataggtaacctgagtcggagcagttttcctcgtggcttcatctttggtgctggatcttcagcataccaatttgaaggtgcagtaaacgaaggcggtagaggaccaagtatttgggataccttcacccataaatatccagaaaaaataagggatggaagcaatgcagacatcacggttgaccaatatcaccgctacaaggaagatgttgggattatgaaggatcaaaatatggattcgtatagattctcaatctcttggccaagaatactcccaaagggaaagttgagcggaggcataaatcacgaaggaatcaaatattacaacaaccttatcaacgaactattggctaacggtatacaaccatttgtaactctttttcattgggatcttccccaagtcttagaagatgagtatggtggtttcttaaactccggtgtaataaatgattttcgagactatacggatctttgcttcaaggaatttggagatagagtgaggtattggagtactctaaatgagccatgggtgtttagcaattctggatatgcactaggaacaaatgcaccaggtcgatgttcggcctccaacgtggccaagcctggtgattctggaacaggaccttatatagttacacacaatcaaattcttgctcatgcagaagctgtacatgtgtataagactaaataccaggcatatcaaaagggaaagataggcataacgttggtatctaactggttaatgccacttgatgataatagcataccagatataaaggctgccgagagatcacttgacttccaatttggattgtttatggaacaattaacaacaggagattattctaagagcatgcggcgtatagttaaaaaccgattacctaagttctcaaaattcgaatcaagcctagtgaatggttcatttgattttattggtataaactattactcttctagttatattagcaatgccccttcacatggcaatgccaaacccagttactcaacaaatcctatgaccaatatttcatttgaaaaacatgggatacccttaggtccaagggctgcttcaatttggatatatgtttatccatatatgtttatccaagaggacttcgagatcttttgttacatattaaaaataaatataacaatcctgcaattttcaatcactgaaaatggtatgaatgaattcaacgatgcaacacttccagtagaagaagctcttttgaatacttacagaattgattactattaccgtcacttatactacattcgttctgcaatcagggctggctcaaatgtgaagggtttttacgcatggtcatttttggactgtaatgaatggtttgcaggctttactgttcgttttggattaaactttgtagattagaaagatggattaaaaaggtaccctaagctttctgcccaatggtacaagaactttctcaaaagaaactagctagtattattaaaagaactttgtagtagattacagtacatcgtttgaagttgagttggtgcacctaattaaataaaagaggttactcttaacatatttttaggccattcgttgtgaagttgttaggctgttatttctattatactatgttgtagtaataagtgcattgttgtaccagaagctatgatcataactataggttgatccttcatgtatcagtttgatgttgagaatactttgaattaaaagtctttttttatttttttaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
     * TO:

     aaacaaacca aatatggatt ttattgtagc catatttgct ctgtttgtta ttagctcatt        60
     cacaattact tccacaaatg cagttgaagc ttctactctt cttgacatag gtaacctgag       120
     tcggagcagt tttcctcgtg gcttcatctt tggtgctgga tcttcagcat accaatttga       180
     aggtgcagta aacgaaggcg gtagaggacc aagtatttgg gataccttca cccataaata       240
     tccagaaaaa ataagggatg gaagcaatgc agacatcacg gttgaccaat atcaccgcta       300
     caaggaagat gttgggatta tgaaggatca aaatatggat tcgtatagat tctcaatctc       360
     ttggccaaga atactcccaa agggaaagtt gagcggaggc ataaatcacg aaggaatcaa       420
     atattacaac aaccttatca acgaactatt ggctaacggt atacaaccat ttgtaactct       480
     ttttcattgg gatcttcccc aagtcttaga agatgagtat ggtggtttct taaactccgg       540
     tgtaataaat gattttcgag actatacgga tctttgcttc aaggaatttg gagatagagt       600
     gaggtattgg agtactctaa atgagccatg ggtgtttagc aattctggat atgcactagg       660
     aacaaatgca ccaggtcgat gttcggcctc caacgtggcc aagcctggtg attctggaac       720
     aggaccttat atagttacac acaatcaaat tcttgctcat gcagaagctg tacatgtgta       780
     taagactaaa taccaggcat atcaaaaggg aaagataggc ataacgttgg tatctaactg       840
     gttaatgcca cttgatgata atagcatacc agatataaag gctgccgaga gatcacttga       900
     cttccaattt ggattgttta tggaacaatt aacaacagga gattattcta agagcatgcg       960
     gcgtatagtt aaaaaccgat tacctaagtt ctcaaaattc gaatcaagcc tagtgaatgg      1020
     ttcatttgat tttattggta taaactatta ctcttctagt tatattagca atgccccttc      1080
     acatggcaat gccaaaccca gttactcaac aaatcctatg accaatattt catttgaaaa      1140
     acatgggata cccttaggtc caagggctgc ttcaatttgg atatatgttt atccatatat      1200
     gtttatccaa gaggacttcg agatcttttg ttacatatta aaaataaata taacaatcct      1260
     gcaattttca atcactgaaa atggtatgaa tgaattcaac gatgcaacac ttccagtaga      1320
     agaagctctt ttgaatactt acagaattga ttactattac cgtcacttat actacattcg      1380
     ttctgcaatc agggctggct caaatgtgaa gggtttttac gcatggtcat ttttggactg      1440
     taatgaatgg tttgcaggct ttactgttcg ttttggatta aactttgtag attagaaaga      1500
     tggattaaaa aggtacccta agctttctgc ccaatggtac aagaactttc tcaaaagaaa      1560
     ctagctagta ttattaaaag aactttgtag tagattacag tacatcgttt gaagttgagt      1620
     tggtgcacct aattaaataa aagaggttac tcttaacata tttttaggcc attcgttgtg      1680
     aagttgttag gctgttattt ctattatact atgttgtagt aataagtgca ttgttgtacc      1740
     agaagctatg atcataacta taggttgatc cttcatgtat cagtttgatg ttgagaatac      1800
     tttgaattaa aagtcttttt ttattttttt aaaaaaaaaa aaaaaaaaaa aaaaaaaaa       1859
     */
    public String getEMBL(){
        StringBuffer sb = new StringBuffer();
        String lastBit = "";
        sb.append("     ");
        int stopVal = this.sequence.length() - this.sequence.length()%60 -1;
        for (int i = 0; i < this.sequence.length(); i++){
            int j = i + 1; //sequence position
            if (i <= stopVal){  //do typical formatting for the majority of the sequence
                sb.append(this.sequence.charAt(i));
                if (j%10==0 && i > 1) sb.append(" ");
            }else {  //handle the gaps that occur on the last line.
                lastBit = lastBit + this.sequence.charAt(i);
                if (j%10==0 && i > 1) lastBit = lastBit + " ";
            }
            if (j%60==0 && i > 0){
                sb.append( formatNumber( j ) );
                sb.append('\n');
                if (i< this.sequence.length() - 60) sb.append("     "); //spaces at the start of the next line
            }
        }
        sb.append(formatFinalLine(lastBit));
        return sb.toString();
    }
    /**
     * format final line actually just backfills the spaces needed
     * lastbit is a string like: tttgaattaa aagtcttttt ttattttttt aaaaaa
     * note it does not contain enough chars
     * @param lastBit
     * @return
     */
    public String formatFinalLine(String lastBit){
        String line = "     ";
        String spaces = "                                                                  ";
        return line + lastBit + spaces.substring(lastBit.length(), spaces.length()) + formatNumber(this.sequence.length()) +  "\n";
    }
    public String formatNumber(int i){
        Integer il = new Integer(i);
        String num = il.toString();
        String spaces = "         ";
        return spaces.substring(0, spaces.length() - num.length()) + num;
    }

    /**
     * Takes as a string an EMBL formatted sequence, s, converts it to a standard
     * string and sets this.sequence to that formatted string.
     * @param s
     */
    public void setEMBL(String s){
        sb = new StringBuffer();
        for (int i = 0; i<s.length(); i++){
            switch ( s.charAt(i) ){
                case '0': ;
                case '1': ;
                case '2': ;
                case '3': ;
                case '4': ;
                case '5': ;
                case '6': ;
                case '7': ;
                case '8': ;
                case '9': ;
                case ' ': ;
                case '\r': ;
                case '\t': ;
                case '\f': ;
                case '\n': ;
                default: sb.append(s.charAt(i));
            }

        }
    }

    /**
     * This implementation uses a hash to only search superString once so
     * DO NOT make substring too long if you value your memory! (m*n)
     * Advantage is that a set of substrings is mapped much faster!
     * @param substring - the string we are attempting to match
     * @param superString = the string we are matchin in
     * @return start, end, strand : sequencePosition of the closest match in superString of the substring (not alignment!)
     */
    public HashMap hashString(String superString, int l){
        HashMap hm = new HashMap();
        for(int i=0;i<superString.length(); i++){
            hm.put(superString.substring(i, i+l), i);
        }
        return hm;
    }
    protected Integer iFoo = new Integer("0");
    public SequencePosition matchWHash(String substring, HashMap hm){
        SequencePosition sp = null;
        int errors = substring.length() + 1;  //worst case
        if (hm.containsKey(substring)){
            int start = (Integer) hm.get(substring);
            int end = start + substring.length();
        }//TODO: test this!!
        return sp;
    }

    public String getTopology() {
        return topology;
    }

    public void setTopology(String topology) {
        this.topology = topology;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    
}
